home *** CD-ROM | disk | FTP | other *** search
/ ftp.qualcomm.com / 2014.06.ftp.qualcomm.com.tar / ftp.qualcomm.com / eudora / developers / emsapi / carbon_emsapi.sit.hqx / Macintosh API Support / ctencode.c < prev    next >
Text File  |  2001-03-08  |  19KB  |  563 lines

  1. /* ======================================================================
  2.  
  3.     Function to encode and decode binary data to quoted-printable data.
  4.     Code extracted from Eudora. Based on Steve Dorner's code.
  5.  
  6.     Filename:            ctencode.c
  7.     Last Edited:        March 7, 1997
  8.     Authors:            Laurence Lundblade, Myra Callen
  9.     Copyright:            1995, 1996 QUALCOMM Inc.
  10.     Technical support:    <emsapi-info@qualcomm.com>
  11. */
  12.  
  13. #include <string.h>
  14. #include "ctencode.h"
  15. #include "rfc822.h"
  16.  
  17. #define SKIP -1
  18. #define FAIL -2
  19. #define PAD  -3
  20. #define kNewLine "\p\r\n"
  21. #define ABS(x)    ((x)<0 ? -(x) : (x))
  22.  
  23. #define kBase64CStr    "base64"
  24. #define kQ_PCStr    "quoted-printable"
  25. #define k7BitCStr    "7bit"
  26. #define k8BitCStr    "8bit"
  27. #define kBinaryCStr    "binary"
  28.  
  29. static UPtr gEncode =
  30.         (UPtr) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  31.  
  32. static short gDecode[] =
  33. {
  34.     FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,SKIP,SKIP,FAIL,FAIL,SKIP,FAIL,FAIL,    /* 0 */
  35.     FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,    /* 1 */
  36.     SKIP,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,0x3e,FAIL,FAIL,FAIL,0x3f,    /* 2 */
  37.     0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,FAIL,FAIL,FAIL,PAD ,FAIL,FAIL,    /* 3 */
  38.     FAIL,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,    /* 4 */
  39.     0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,FAIL,FAIL,FAIL,FAIL,FAIL,    /* 5 */
  40.     FAIL,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,    /* 6 */
  41.     0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,FAIL,FAIL,FAIL,FAIL,FAIL,    /* 7 */
  42.     FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,    /* 8 */
  43.     FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,    /* 9 */
  44.     FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,    /* A */
  45.     FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,    /* B */
  46.     FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,    /* C */
  47.     FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,    /* D */
  48.     FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,    /* E */
  49.     FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,FAIL,    /* F */
  50.   /* 0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F  */
  51. };
  52.  
  53. /*
  54.  * the encoding is like this:
  55.  *
  56.  * Binary:<111111><222222><333333>
  57.  *          765432107654321076543210
  58.  * Encode:<1111><2222><3333><4444>
  59.  */
  60.  
  61. /* Bit extracting macros */
  62. #define Bot2(b) ((b)&0x3)
  63. #define Bot4(b) ((b)&0xF)
  64. #define Bot6(b) ((b)&0x3F)
  65. #define Top2(b) Bot2((b)>>6)
  66. #define Top4(b) Bot4((b)>>4)
  67. #define Top6(b) Bot6((b)>>2)
  68.  
  69.  
  70. /************************************************************************
  71.  * Encode64 - convert binary data to base64
  72.  *  binPtr         ->    the binary data (or nil to close encoder)
  73.  *    binLen         -> the length of the binary data
  74.  *  sixFourPtr     -> pointer to buffer for the base64 data
  75.  *    sixFourLen    <-    the length of the base64 data
  76.  *  e64            <-> state; caller must preserve
  77.  *  returns kCTEDoneOK or kCTEFailed
  78.  ************************************************************************/
  79. short Encode64(const UPtr binPtr, long binLen,
  80.                const UPtr sixFourPtr, long *sixFourBufSize, Enc64Ptr e64)
  81. {
  82.     UPtr         binSpot;                    /* the byte currently being decoded */
  83.     UPtr         sixFourSpot = sixFourPtr;    /* the spot to which to copy the encoded chars */
  84.     short         bpl;
  85.     UPtr        end, bPtr;                        /* end of integral decoding */
  86.     PStr        newLine = kNewLine;
  87.  
  88.     bpl = e64->bytesOnLine;                    /* in inner loop; want local copy */
  89.     bPtr = (UPtr) binPtr;
  90.     if (binLen) {
  91.         
  92.         if (e64->partialCount) {        // do we have any stuff left from last time?
  93.             short needMore = 3 - e64->partialCount;
  94.             if (binLen >= needMore) {    // we can encode some bytes
  95.                 BlockMoveData(bPtr, e64->partial + e64->partialCount, needMore);
  96.                 binLen -= needMore;
  97.                 bPtr += needMore;
  98.  
  99.                 do {
  100.                     if ((bpl) == 68) {
  101.                         int m_nl;
  102.                         for (m_nl = 0; m_nl < *(newLine); )
  103.                             *(sixFourSpot)++ = (newLine)[++m_nl];
  104.                         (bpl) = 0;
  105.                     }
  106.                     (bpl) += 4;
  107.                     *(sixFourSpot)++ = gEncode[Top6((e64->partial)[0])];
  108.                     *(sixFourSpot)++ = gEncode[Bot2((e64->partial)[0]) << 4 |
  109.                                             Top4((e64->partial)[1])];
  110.                     *(sixFourSpot)++ = gEncode[Bot4((e64->partial)[1]) << 2 |
  111.                                             Top2((e64->partial)[2])];
  112.                     *(sixFourSpot)++ = gEncode[Bot6((e64->partial)[2])];
  113.                 }
  114.                 while (0);
  115.  
  116.                 if (*sixFourBufSize <  sixFourSpot - sixFourPtr)
  117.                     return(kCTEFailed);
  118.  
  119.                 e64->partialCount = 0;
  120.             }
  121.             /*
  122.              * if we don't have enough bytes to complete the leftovers, we
  123.              * obviously don't have 3 bytes.  So the encoding code will fall
  124.              * through to the point where we copy the leftovers to the partial
  125.              * buffer.  As long as we're careful to append and not copy blindly,
  126.              * we'll be fine.
  127.              */
  128.         }
  129.  
  130.         // we encode the integral multiples of three
  131.         end = bPtr + 3*(binLen/3);
  132.         for (binSpot = bPtr; binSpot < end; binSpot += 3) {
  133.             do {
  134.                 if ((bpl)==68) {
  135.                     int m_nl;
  136.                     for (m_nl=0;m_nl<*(newLine);)
  137.                         *(sixFourSpot)++ = (newLine)[++m_nl];
  138.                     (bpl) = 0;
  139.                 }
  140.                 (bpl) += 4;
  141.                 *(sixFourSpot)++ = gEncode[Top6((binSpot)[0])];
  142.                 *(sixFourSpot)++ = gEncode[Bot2((binSpot)[0])<<4 | Top4((binSpot)[1])];
  143.                 *(sixFourSpot)++ = gEncode[Bot4((binSpot)[1])<<2 | Top2((binSpot)[2])];
  144.                 *(sixFourSpot)++ = gEncode[Bot6((binSpot)[2])];
  145.             }
  146.             while (0);
  147.  
  148.             if (*sixFourBufSize <  sixFourSpot - sixFourPtr)
  149.                     return(kCTEFailed);
  150.         }
  151.         // now, copy the leftovers to the partial buffer
  152.         binLen = binLen % 3;
  153.         if (binLen) {
  154.             BlockMoveData(binSpot,e64->partial+e64->partialCount,binLen);
  155.             e64->partialCount += binLen;
  156.         }
  157.     }
  158.     else {    // we've been called to cleanup the leftovers
  159.         if (e64->partialCount) {
  160.             if (e64->partialCount<2) e64->partial[1] = 0;
  161.             e64->partial[2] = 0;
  162.  
  163.             do {
  164.                 if ((bpl)==68) {
  165.                     int m_nl;
  166.                     for (m_nl=0;m_nl<*(newLine);)
  167.                         *(sixFourSpot)++ = (newLine)[++m_nl];
  168.                     (bpl) = 0;
  169.                 }
  170.                 (bpl) += 4;
  171.                 *(sixFourSpot)++ = gEncode[Top6((e64->partial)[0])];
  172.                 *(sixFourSpot)++ = gEncode[Bot2((e64->partial)[0])<<4 | Top4((e64->partial)[1])];
  173.                 *(sixFourSpot)++ = gEncode[Bot4((e64->partial)[1])<<2 | Top2((e64->partial)[2])];
  174.                 *(sixFourSpot)++ = gEncode[Bot6((e64->partial)[2])];
  175.             }
  176.             while (0);
  177.  
  178.             if (*sixFourBufSize <  sixFourSpot - sixFourPtr)
  179.                     return(kCTEFailed);
  180.  
  181.             // now, replace the unneeded bytes with ='s
  182.             sixFourSpot[-1] = '=';
  183.             if (e64->partialCount==1) sixFourSpot[-2] = '=';
  184.         }
  185.     }
  186.     e64->bytesOnLine = bpl;                         /* copy back to state buffer */
  187.     *sixFourBufSize = sixFourSpot - sixFourPtr;  /* return actual buffer size */
  188.  
  189.     return kCTEDoneOK;
  190. }
  191.  
  192.  
  193.  
  194. /************************************************************************
  195.  * Decode64 - convert base64 data to binary
  196.  *  sixFourPtr     ->    the base64 data (or nil to close decoder)
  197.  *  sixFourLen     -> the length of the base64 data
  198.  *  binPtr         -> pointer to buffer to hold binary data
  199.  *  binBufSize    <-    length of binary data
  200.  *  d64            <->    pointer to decoder state
  201.  *    decErrCnt    <-    the number of decoding errors found
  202.  *  returns kCTEDoneOK or kCTEFailed
  203.  ************************************************************************/
  204. short Decode64(const UPtr sixFourPtr, long sixFourLen,
  205.                const UPtr binPtr, long *binBufSize,
  206.                const Dec64Ptr d64, long *decErrCnt)
  207. {
  208.     short         decode;                            /* the decoded short */
  209.     Byte         c;                                /* the decoded byte */
  210.         /* we separate the short & the byte so the compiler can worry about byteorder */
  211.     UPtr         end = sixFourPtr + sixFourLen;    /* stop decoding here */
  212.     UPtr         binSpot = binPtr;                /* current output character */
  213.     short         decoderState;                    /* which of 4 bytes are we seeing now? */
  214.     long         invalCount;                        /* how many bad chars found this time around? */
  215.     long         padCount;                        /* how many pad chars found so far? */
  216.     Byte         partial;                        /* partially decoded byte from/for last/next time */
  217.     Boolean        wasCR;
  218.     UPtr        pSixFour, sixFourStartPtr;
  219.  
  220.     decoderState = d64->decoderState;    // fetch state from caller's buffer
  221.     invalCount = 0;    /* we'll add the invalCount to the buffer later */
  222.     padCount = d64->padCount;
  223.     partial = d64->partial;
  224.     wasCR = d64->wasCR;
  225.     pSixFour = (UPtr) sixFourPtr;
  226.  
  227.     if (sixFourLen) {
  228.         sixFourStartPtr = pSixFour;
  229.         for ( ; pSixFour < end; pSixFour++) {
  230.             switch(decode=gDecode[*pSixFour]) {
  231.                 case SKIP: break;                        /* skip whitespace */
  232.                 case FAIL: invalCount++; break;            /* count invalid characters */
  233.                 case PAD: padCount++; break;            /* count pad characters */
  234.                 default:
  235.                     if (padCount) {        // found a non-pad character
  236.                         invalCount += padCount;
  237.                         padCount = 0;    // prev pad was an error
  238.                     }
  239.                     c = decode;            // extract the right bits
  240.                     switch (decoderState) {
  241.                         case 0:
  242.                             partial = c<<2;
  243.                             decoderState++;
  244.                             break;
  245.                         case 1:
  246.                             *binSpot++ = partial|Top4(c);
  247.                             partial = Bot4(c)<<4;
  248.                             decoderState++;
  249.                             break;
  250.                         case 2:
  251.                             *binSpot++ = partial|Top6(c);
  252.                             partial = Bot2(c)<<6;
  253.                             decoderState++;
  254.                             break;
  255.                         case 3:
  256.                             *binSpot++ = partial|c;
  257.                             decoderState=0;
  258.                             break;
  259.                     }
  260.             }
  261.             /* make sure we're not writing past the end of the buffer */
  262.             if (*binBufSize <  binSpot - binPtr)
  263.                 return(kCTEFailed);
  264.         } /* for pSixFour */
  265.     } /* if sixFourLen */
  266.     else {            // all done.  Did all end up evenly?
  267.         switch (decoderState) {
  268.             case 0:
  269.                 invalCount += padCount;            /* came out evenly, so should be no pads */
  270.                 break;
  271.             case 1:
  272.                 invalCount++;                    /* data missing */
  273.                 invalCount += padCount;            /* since data missing; should be no pads */
  274.                 break;
  275.             case 2:
  276.                 invalCount += ABS(padCount-2);    /* need exactly 2 pads */
  277.                 break;
  278.             case 3:
  279.                 invalCount += ABS(padCount-1);    /* need exactly 1 pad */
  280.                 break;
  281.         }
  282.     }
  283.     *binBufSize = binSpot - binPtr;       /* return actual buffer size */
  284.  
  285.     // save state in caller's buffer
  286.     d64->decoderState = decoderState;
  287.     d64->invalCount += invalCount;
  288.     d64->padCount = padCount;
  289.     d64->partial = partial;
  290.     d64->wasCR = wasCR;
  291.  
  292.     *decErrCnt = invalCount;
  293.     return kCTEDoneOK;
  294. }
  295.  
  296.  
  297.  
  298. /************************************************************************
  299.  * EncodeQP - convert binary data to quoted-printable
  300.  *  binPtr -> the binary data
  301.  *    binLen -> the length of the binary data (or nil to close encoder)
  302.  *  qpPtr -> pointer to buffer for the quoted-printable data
  303.  *    qpBufSize <-> length of the quoted-printable buffer, returns actual length
  304.  *  eQP <-> encoder state for bytes per line; caller must preserve
  305.  *  returns kCTEDoneOK or kCTEFailed
  306.  ************************************************************************/
  307. long EncodeQP(const UPtr binPtr, long binLen,
  308.               const UPtr qpPtr, long *qpBufSize, long *eQP)
  309. {
  310.     UPtr             binSpot = binPtr;        /* the byte currently being decoded */
  311.     UPtr             qpSpot = qpPtr;            /* the spot to which to copy the encoded chars */
  312.     UPtr            binEndPtr;                /* stop decoding line here */
  313.     short             bpl, c;
  314.     static char     *hex="0123456789ABCDEF";
  315.     Boolean         encode;
  316.     UPtr             nextSpace;
  317.     PStr            newLine = kNewLine;
  318.  
  319. #define ROOMFOR(x)                                                \
  320.     do {                                                        \
  321.         if (bpl + x > 76) {                                        \
  322.             *qpSpot++ = '=';                                    \
  323.             do {                                                \
  324.                 BlockMoveData(newLine+1,qpSpot,*newLine);        \
  325.                 qpSpot += *newLine;                                \
  326.                 bpl = 0;                                        \
  327.             } while (0);                                        \
  328.         }                                                                                                \
  329.     } while(0)
  330.  
  331.     bpl = *eQP;        /* in inner loop; want local copy */
  332.     if (binLen && binPtr) {
  333.         binEndPtr = binPtr + binLen;
  334.  
  335.         for (binSpot = binPtr; binSpot < binEndPtr; binSpot++) {
  336.             /* fail if we try to write beyond the output buffer size */
  337.             if (*qpBufSize + 4 <  qpSpot - qpPtr)
  338.                     return(kCTEFailed);
  339.  
  340.             c = *binSpot;            // make copy of char
  341.             if (c == newLine[1])    // handle newlines
  342.                 do {
  343.                     BlockMoveData(newLine+1,qpSpot,*newLine);
  344.                     qpSpot += *newLine;
  345.                     bpl = 0;
  346.                 } while (0);
  347.  
  348.             else if ((c == '\n') || (c == '\r'))
  349.                 ;    /* skip other newline characters */
  350.             else {
  351.                 if ((c == ' ') || (c == '\t')) {        /* trailing white space */
  352.                     encode = ((binSpot == binEndPtr - 1) || (binSpot[1] == '\r'));
  353.                     if (!encode) {
  354.                         for(nextSpace = binSpot + 1; nextSpace < binEndPtr; nextSpace++)
  355.                             if ((*nextSpace == ' ') || (*nextSpace == '\r')) {
  356.                                 if ((nextSpace - binSpot) < 20)  ROOMFOR(nextSpace - binSpot);
  357.                                 break;
  358.                             }
  359.                     }
  360.                 }
  361.                 else
  362.                     encode =  (c == '=') || (c < 33) || (c > 126);    /* weird characters */
  363.  
  364.                 if (encode)
  365.                     ROOMFOR(3);
  366.                 else
  367.                     ROOMFOR(1);
  368.  
  369.                 encode = encode || !bpl && ((c == 'F') || (c == '.'));
  370.  
  371.                 if (encode) {
  372.                     *qpSpot++ = '=';
  373.                     *qpSpot++ = hex[(c>>4)&0xf];
  374.                     *qpSpot++ = hex[c&0xf];
  375.                     bpl += 3;
  376.                 }
  377.                 else {
  378.                     *qpSpot++ = c;
  379.                     bpl++;
  380.                 }
  381.             } /* else */
  382.         }    /* for */
  383.     }    /* if binLen */
  384.     *eQP = bpl;                        /* copy back to state buffer */
  385.     *qpBufSize = qpSpot - qpPtr;      /* return actual buffer size */
  386.  
  387.     return kCTEDoneOK;
  388. }
  389.  
  390.  
  391. #define HEX(c)    ((c) >= '0' && (c) <= '9' ? (c) - '0' : \
  392.                 ((c) >= 'A' && (c) <= 'F' ? (c) - 'A' + 10 : \
  393.                 ((c) >= 'a' && (c) <= 'f' ? (c) - 'a' + 10 : -1)))
  394. /************************************************************************
  395.  * DecodeQP - convert quoted printable data to binary
  396.  *  qpStartPtr     -> the quoted printable data
  397.  *  qpLen         -> the length of the quoted printable data (or nil to close decoder)
  398.  *  binPtr         -> pointer to buffer to hold binary data
  399.  *  binBufSize  <-> the length of the binary buffer, returns actual length
  400.  *  dQP            <-> pointer to decoder state; caller must preserve
  401.  *    decErrCnt    <-    the number of decoding errors found
  402.  *  returns kCTEDoneOK or kCTEFailed
  403.  * Note: this does not do conversion to local newline convention as the
  404.  *       Eudora internal version does (Maybe a flag to select would be good?)
  405.  ************************************************************************/
  406. long DecodeQP(const UPtr qpPtr, long qpLen,
  407.               const UPtr binPtr, long *binBufSize,
  408.               const DecQPPtr dQP, long *decErrCnt)
  409. {
  410.     Byte            c;                        /* the decoded byte */
  411.     UPtr            binSpot = binPtr;        /* current output character */
  412.     UPtr            qpSpot = qpPtr;            /* current input character */
  413.     UPtr            qpEndPtr;                /* stop decoding line here */
  414.     QPStates        state;
  415.     Byte            lastChar;
  416.     short            upperNib, lowerNib, errs = 0;
  417.     long            spaceCnt, cnt;
  418.  
  419.     state = dQP->state;        // fetch state from caller's buffer
  420.     lastChar = dQP->lastChar;
  421.     spaceCnt = dQP->spaceCount;
  422.  
  423.     if (qpLen && qpPtr) {
  424.         qpEndPtr = qpPtr + qpLen;
  425.         for (qpSpot = qpPtr; qpSpot < qpEndPtr; qpSpot++) {
  426.             c = *qpSpot;
  427.             switch (state) {
  428.                 case qpNormal:
  429.                     if (c == ' ') {
  430.                         spaceCnt++;
  431.                     }
  432.                     else if (c == '=') {
  433.                         for (cnt = 0; cnt < spaceCnt; cnt++)
  434.                             *binSpot++ = ' ';
  435.                         state = qpEqual;
  436.                         spaceCnt = 0;
  437.                     }
  438.                     else if (c == '\r' || c == '\n') {
  439.                         *binSpot++ = c;
  440.                         spaceCnt = 0;                    // Ignore spaces before CR
  441.                     }
  442.                     else {
  443.                         for (cnt = 0; cnt < spaceCnt; cnt++)
  444.                             *binSpot++ = ' ';
  445.                         *binSpot++ = c;
  446.                         spaceCnt = 0;
  447.                     }
  448.                     break;
  449.  
  450.                 case qpEqual:
  451.                     if (c == ' ') {
  452.                         spaceCnt++;
  453.                     }
  454.                     else if (c == '\r' || c == '\n') {
  455.                         state = qpNormal;
  456.                         spaceCnt = 0;                    // Ignore spaces between Equal and CR
  457.                     }
  458.                     else
  459.                         state = qpByte1;
  460.                     break;
  461.  
  462.                 case qpByte1:
  463.                     upperNib = HEX(lastChar);
  464.                     lowerNib = HEX(c);
  465.                     if ((upperNib < 0) || (lowerNib < 0))
  466.                         errs++;
  467.                     else
  468.                         *binSpot++ = (upperNib<<4) | lowerNib;
  469.                     state = qpNormal;
  470.                     break;
  471.             }
  472.             lastChar = c;
  473.         }    /* for */
  474.     }    /* if qpLen */
  475.     else if (state != qpNormal)
  476.         errs++; /* when closing decoder */
  477.  
  478.     // save state in caller's buffer
  479.     dQP->state = state;
  480.     dQP->lastChar = lastChar;
  481.     dQP->spaceCount = spaceCnt;
  482.     *binBufSize = binSpot - binPtr;
  483.  
  484.     *decErrCnt = errs;
  485.     return kCTEDoneOK;
  486. }
  487.  
  488. #pragma mark -
  489.  
  490. /************************************************************************
  491.  * RFC822_ParseCTE - parse Content-Transer-Encoding header line
  492.  *  src              ->    Valid Transfer-Encoding header
  493.  *  returns enumerated integer 'TrEncType' type specifying CTE.
  494.  ************************************************************************/
  495. TrEncType RFC822_ParseCTE(const char *src)
  496. {
  497.     const unsigned short    kPrefixStrLen = strlen(kCTEncodeHdrCStr);
  498.     char                    *cp = (char *) src + kPrefixStrLen, *mechanism = nil;
  499.     TrEncType                cte = CTE_Error;
  500.  
  501.     if (strncmp(src, kCTEncodeHdrCStr, kPrefixStrLen) == 0) {    // Check prefix
  502.         // Get first token (skips whitespace/comments)
  503.         mechanism = RFC822_ExtractToken(&cp);
  504.         if ((mechanism) && (strlen(mechanism) > 0)) {
  505.             if (strcmp(mechanism, kBase64CStr) == 0)
  506.                 cte = CTE_Base64;
  507.             else if (strcmp(mechanism, kQ_PCStr) == 0)
  508.                 cte = CTE_QP;
  509.             else if (strcmp(mechanism, k7BitCStr) == 0)
  510.                 cte = CTE_7bit;
  511.             else if (strcmp(mechanism, k8BitCStr) == 0)
  512.                 cte = CTE_8bit;
  513.             else if (strcmp(mechanism, kBinaryCStr) == 0)
  514.                 cte = CTE_Binary;
  515.         }
  516.         DisposePtr(mechanism);
  517.     }
  518.     return (cte);
  519. }
  520.  
  521.  
  522. /************************************************************************
  523.  * RFC822_MakeCTE - create Content-Transer-Encoding header line
  524.  * NOTE: The user of this function is responsible for freeing the
  525.  * returned string.
  526.  *  mechanism      ->    enumerated integer 'TrEncType' type specifying CTE
  527.  *  returns content tranfer encoding header line string.
  528.  ************************************************************************/
  529. Handle RFC822_MakeCTE(TrEncType mechanism)
  530. {
  531.     char        s[80];
  532.     Handle        h;
  533.  
  534.     strcpy(s, kCTEncodeHdrCStr);
  535.     strcat(s, " ");
  536.     switch (mechanism) {
  537.         case CTE_Base64:    strcat(s, kBase64CStr);        break;
  538.         case CTE_QP:        strcat(s, kQ_PCStr);        break;
  539.         case CTE_7bit:        strcat(s, k7BitCStr);        break;
  540.         case CTE_8bit:        strcat(s, k8BitCStr);        break;
  541.         case CTE_Binary:    strcat(s, kBinaryCStr);        break;
  542.         default:
  543.             return nil;
  544.     }
  545.     PtrToHand(s, &h, strlen(s));
  546.     return h;
  547. }
  548.  
  549.  
  550. /************************************************************************
  551.  * RFC822_ExtractCTE - finds and extracts the content transfer encoding
  552.  * header line from a full multi-lined header.
  553.  * All unfolding (removing newlines) is done before header line is returned.
  554.  * NOTE: The user of this function is responsible for freeing the
  555.  * returned string.
  556.  *  pFullHeader      ->    pointer to a full RFC822 header, including newlines
  557.  *  returns extracted header line string; dynamically allocated
  558.  ************************************************************************/
  559. char *RFC822_ExtractCTE(const char *pFullHeader)
  560. {
  561.     return RFC822_ExtractHeader(pFullHeader, kCTEncodeHdrCStr);
  562. }
  563.